;Jakub Pilch
;Informatyka IEiT

pcrc equ 18005h						;wielomian CRC-16 (x^16 + x^15 + x^2 + 1).

data segment
        tabl db 127 dup (?)             ;tablica 127 elementów po 1 bajcie (max input)
        licz dw 1                       ;licznik przeladowanych danych
        argz dw 1                       ;licznik argrumentow (oddzielonych spacjami/tabulatorem)
        lent dw 6       dup     (0)     ;miara dlugosci argumentow (oraz adresy ich poczatkow)
                                        ;tablica postaci: [adres][dlugosc][adres][dlugosc]...
        flaga dw 1                      ;flaga oczekiwania na argument.
                nzwi1 db 127    dup (?) ;nazwa pliku do odczytu (input/input1).
                nzwi2 db 127    dup (?) ;nazwa pliku do odczytu 2 (intput2).
                nzwo db 127     dup (?) ;nazwa pliku do zapisu (output).
                grip1 dw ?              ;uchwyt do pliku 1.
                grip2 dw ?              ;uchwyt do pliku 2.
                buffer db 500    dup (0) ;bufor odczytu
				crcbuffer db 60 dup (0) ;bufor odczytu sum CRC-16.
				buflen dw 1				;dlugosc danych wczytanych;
				crcbuflen dw 1			;dlugosc danych sum CRC-16.
				line db 200 dup (?)		;cala linijka tutaj;
				crcline db 4 dup (?)	;jedna pobrana suma CRC-16.
				alread dw 1				;ile znakow faktycznie przeczytano z bufora.
				crcalread dw 1			;ile znakow sum CRC-16 faktycznie przeczytano.
				rev dw 1				;zmienna do odwracania bitow.
				crctab dw 256 dup (?)	;tablica pomocnicza do obliczania CRC.
				tstrev dw 1				;zmienna pomocnicza przy obliczeniach CRC.
				crc	dw	1				;zmienna do obliczania CRC.
				eof db 1				;flaga konca pliku.
				crcpack db 6 dup (?)	;sumy CRC do zapisu
				currentbuf dw 1 		;aktualne polozenie w buforze.
				crccurrbuf dw 1			;aktualne polozenie w buforze CRC-16.
				crcread	dw 1			;suma CRC z odczytana z pliku (do porownania).
				mulkeeper dw 1			;do przechowywania aktualnego mnoznika.
				crceof db 1				;flaga konca pliku z sumami CRC.
				linecount dw 1			;licznik linii w czasie odczytu.

                inferr dw 1             ;info o rodzaju bledu.
                komu1 db "Blad danych: zla liczba argumentow (oczekiwano 2 lub 3).$"
				komu2 db "Blad danych: parametr 1 jest rozny od '-v'$"
				komu3 db "Blad danych: zle dlugosci argumentow.$"
                komu4 db "Blad odczytu z pliku - plik nie zostal odnaleziony.$"
                komu5 db "Blad odczytu/zapisu - brak dostepu do pliku.$"
				komu6 db "Wystapil nieoczekiwany blad podczas zamkniecia pliku.$"
				komu7 db "Niezgodnosc sum kontrolnych w linii nr $"
				komu8 db "Blad: plik 2 nie zawiera wystarczajaco wielu sum kontrolnych.$"
				komu9 db "Zapis sum CRC-16 do pliku zakonczony powodzeniem.$"
				komu10 db "Porownanie sum CRC-16 zakonczone powodzeniem - nie wykryto niezgodnosci.$"
				
data ends
;-------------------------------

stack segment stack
        dw      256 dup (?)           	;stos 256 * 2 bajty
top     dw      ?                       ;wierzcholek stosu
stack ends

;------------------------

code segment
        ;==============================LOADER===========================================
         LOADER proc                            ;laduje argumenty do tabl
                                                ;seg tablicy wejsciowej w ES
                                                ;seg danych w DS
                push ax                         ;ladowanie rejestrow na stos
                push bx                         ;celem przywrocenia ich na koncu
                push cx                         ;procedury
                push dx
                mov di,offset tabl              ;początek docelowej tablicy
                mov si,82h                      ;w 81h jest spacja
                mov ch,byte ptr es:[80h]        ;licznik argumentow z wiersza polecen
                ;-----------------------------------------------
                cmp ch,0d                       ;jesli wywolano bez argumentow
                JE  stoper                      ;skocz na koniec
                cmp ch,1d                       ;jesli wywolano z jednym argumentem
                JE  stoper                      ;czyli spacja, skocz na koniec
                ;-----------------------------------------------
                mov ax,0                        ;zerowanie licznika przeniesionych danych
                mov ds:[licz],ax                ;licznik przeniesionych arg. wyzerowany
                mov ax,0                        ;poczatkowa ilosc argumentow.
                mov ds:[argz],ax                ;licznik arg. oddzielonych bialym znakiem =0.
                mov dx,1d
                mov ds:[flaga],dx               ;flaga oczekiwania=TRUE.
                mov bx,offset lent              ;offset tablicy dlugosci argumentow do BX.
                dec bx                          ;oczekujemy "przed" tablica na pierwszy arg.
                ;-----------------------------------------------
        whspace:
                cmp ch,1d                       ;czy juz nie ma czego przenosic?
                JE  stoper                      ;jeśli tak, skocz do stoper
                mov ah,es:[si]                  ;przenosimy porownywany el. do ah
                cmp ah,20h                      ;czy wczytany znak to spacja?
                JNE whtab                       ;jesli nie, skocz do whtab.

                inc si                          ;jestli tak to przesun offset wejscia
                dec ch                          ;zmniejsz licznik arg. do przeniesienia
                mov dx,1d
                mov ds:[flaga],dx               ;flaga oczekiwania=TRUE.
                JMP whspace                     ;sprawdzamy od nowa
                ;-----------------------------------------------
        whtab:
                cmp ah,9h                       ;czy wczytany znak to tabulacja?
                JNE finish                      ;jesli nie, skocz do finish

                inc si                          ;jesli tak, przesun offset wejscia
                dec ch                          ;zmniejsz licznik arg. do przeniesienia
                mov dx,1d
                mov ds:[flaga],dx  				;flaga oczekiwania=TRUE.
                JMP whspace                     ;i skok do sprawdzania spacji
                ;-----------------------------------------------
        finish:

                mov ds:[di],ah                  ;przerzut do tablicy docelowej
                inc si                          ;przesuwamy offset wejscia
                dec ch                          ;zmniejszamy licznik arg. do przeniesienia
                inc ds:[licz]                   ;zwiekszamy licznik przeniesionych argumentow

				cmp ds:[flaga],1d               ;czy oczekiwano na argument?
				JNE conti                       ;jesli nie, kontynuuj przeladowanie.
				mov dx,0d                       ;jesli tak:
				mov ds:[flaga],dx               ;flaga oczekiwania=FALSE.
				inc ds:[argz]                   ;zwieksz licznik argumentow
				mov dx,3d
                cmp ds:[argz],dx                ;porownanie z limitem argumentow
                JA argerr                   	;jesli przekroczony, skok do komuniaktu o bledzie.
                inc bx                      	;jesli nie, przesuwamy sie w tablicy [lent].
                mov [bx],di             		;jako poczatek kolejnego argumentu: aktualne polozenie w [tabl]
                inc bx                      	;przesuwamy sie do licznika dlugosci kolejnego argumentu[lent]


            conti:
                inc di                          ;przesuwamy sie w tablicy docelowej
                mov ax,1d
                add ds:[bx],ax                  ;zwiekszamy licznik dlugosci argumentu.
                JMP whspace                 	;i sprawdzamy kolejny znak

                ;-------------Powrot do programu----------------------
                stoper:
                pop dx                  ;przywracamy rejestry
                pop cx
                pop bx
                pop ax
                ret                     ;powrot do programu
        LOADER endp

                ;===============================CHECKUP==================================

		CHECKUP proc                        ;procedura CHECKUP sprawdza poprawnosc
				push ax                 	;danych przeniesionych do tablicy [tabl]
				push bx                     ;przez procedure LOADER pod katem
				push cx                     ;ilosci oraz poprawnosci argumentow.
				push dx

		;-------------Sprawdzenie ilosci argumentow---------------
				cmp ds:[argz],2d        	;sprawdzenie, czy wywolano z wlasciwa iloscia argumentow
				JNE mb3                 	;jesli nie 2 argumenty, skaczemy do mb3.
				JMP getback                 ;jesli tak, skocz do getback.
		mb3:
				cmp ds:[argz],3d            ;czy 3 argumenty?
				JNE argerr                  ;jesli nie, blad.
				JMP ver2                    ;jesli tak, skocz do wersji 2.

		;----Sprawdzenie dlugosci/poprawnosci parametru 1.-------------
			ver2:                           ;jezeli 3 argumenty, czy pierwszy to "-v"?
				mov bx,offset lent
				inc bx                  	;na drugim miejscu [lent] jest dlugosc 1. arg.
				mov cl,2h
				cmp [bx],cl             	;czy dlugosc argumentu 1 jest rowna 2 ("-v")?
				JNE arglenerr       		;jesli nie, skocz do bledu.

				mov di,offset tabl          ;sprawdzanie 1. znaku pierwszego argumentu
				mov ah,"-"                  ;"-" w kodzie ASCII
				cmp ds:[di],ah              ;jezeli argument pierwszy jest rozny od "-"
				JNE  argtypeerr             ;skaczemy do komunikatu o bledzie.
				inc di                      ;sprawdzenie drugiego znaku
				mov ah,"v"                  ;"v" w kodzie ASCII
				cmp ds:[di],ah              ;jezeli argument pierwszy jest rozny od "v"
				JNE  argtypeerr             ;skaczemy do komunikatu o bledzie.

			;-------------Powrot do programu----------------------
			getback:
				pop dx                      ;przywracamy rejestry
				pop cx
				pop bx
				pop ax
				ret                     	;powrot do programu
		CHECKUP endp

                ;==========================OPENTWO=====================================

		OPENTWO proc                                 	;procedura wczytuje nazwy dwoch plikow
						push ax                         ;input oraz output
						push bx                         ;i zapisuje je do odpowiednio nzw1 i nzw3
						push cx
						push dx
				;--------------------------------------------
						mov si,offset nzwi1             ;offset nazwy pliku do oczytu
						mov di,offset lent
						xor bx,bx
						mov bl,byte ptr ds:[di]         ;adres poczatku nazwy1 w tabl
						xor cx,cx
						mov cl,byte ptr ds:[di+1]       ;dlugosc nazwy1
				nazwaxi:
						mov al,ds:[bx]          		;jeden znak nazwy1 do al
						mov ds:[si],al          		;a nastepnie do nzw1
						inc si                          ;przesuniecie offsetu w obu tablicach
						inc bx
						loop nazwaxi            		;powtarzaj dla kazdego znaku nazwy1.

						mov al,0d                       ;nazwa pliku musi byc zakonczona NULLem.
						mov ds:[si],al
				;---------------------------------------------
						mov si,offset nzwo              ;offset nazwy pliku do zapisu
						mov di,offset lent
						xor bx,bx
						mov bl,byte ptr ds:[di+2]       ;adres poczatku nazwyo w tabl
						xor cx,cx
						mov cl,byte ptr ds:[di+3]       ;dlugosc nazwyo
				nazwaxo:
						mov al,ds:[bx]          		;jeden znak nazwyo do al
						mov ds:[si],al        		  	;a nastepnie do nzw3
						inc si                          ;przesuniecie offsetu w obu tablicach
						inc bx
						loop nazwaxo            		;powtarzaj dla kazdego znaku nazwyo.

						mov al,0d                       ;nazwa pliku musi byc zakonczona NULLem.
						mov ds:[si],al
				;-------------------------------------------
						mov dx,offset nzwi1
						mov al,0d                       ;plik tylko do odczytu.
						mov ah,3Dh                      ;proba otwarcia pliku
						int 21h
						JC      fileerr                 ;w razie bledu skok do fileerr
						mov ds:[grip1],ax       		;uchwyt do pliku w grab1.

						mov dx,offset nzwo
						mov al,1d                       ;plik tylko do zapisu
						mov ah,3Dh                      ;proba otwarcia
						int 21h
						JC fileerr                      ;w razie bledu skok do fileerr
						mov ds:[grip2],ax       		;uchwyt do pliku w grab2

						pop dx                          ;przywrocenie rejestrow i powrot do programu.
						pop cx
						pop bx
						pop ax
						ret

		OPENTWO endp

        ;===========================OPENTHREE====================================

		OPENTHREE proc                              	;procedura wczytuje nazwy dwoch plikow
						push ax                         ;input1 oraz input2
						push bx                         ;i zapisuje je do odpowiednio nzwi1 i nzwi2
						push cx
						push dx
				;--------------------------------------------
						mov si,offset nzwi1             ;offset nazwy pliku do oczytu
						mov di,offset lent
						xor bx,bx
						mov bl,byte ptr ds:[di+2]       ;adres poczatku nazwy1 w tabl
						xor cx,cx
						mov cl,byte ptr ds:[di+3]       ;dlugosc nazwy1
				nazwax:
						mov al,ds:[bx]          		;jeden znak nazwy1 do al
						mov ds:[si],al          		;a nastepnie do nzw1
						inc si                          ;przesuniecie offsetu w obu tablicach
						inc bx
						loop nazwax                     ;powtarzaj dla kazdego znaku nazwy1.

						mov al,0d                       ;nazwa pliku musi byc zakonczona NULLem.
						mov ds:[si],al
				;---------------------------------------------
						mov si,offset nzwi2             ;offset nazwy pliku do odczytu2
						mov di,offset lent
						xor bx,bx
						mov bl,byte ptr ds:[di+4]       ;adres poczatku nazwy2 w tabl
						xor cx,cx
						mov cl,byte ptr ds:[di+5]       ;dlugosc nazwy2
				nazwaxii:
						mov al,ds:[bx]          		;jeden znak nazwy2 do al
						mov ds:[si],al          		;a nastepnie do nzwi2
						inc si                          ;przesuniecie offsetu w obu tablicach
						inc bx
						loop nazwaxii           		;powtarzaj dla kazdego znaku nazwy2.

						mov al,0d                       ;nazwa pliku musi byc zakonczona NULLem.
						mov ds:[si],al
				;-------------------------------------------
						mov dx,offset nzwi1
						mov al,0d                       ;plik tylko do odczytu.
						mov ah,3Dh                      ;proba otwarcia pliku
						int 21h
						JC      fileerr                 ;w razie bledu skok do fileerr
						mov ds:[grip1],ax       		;uchwyt do pliku w grab1.

						mov dx,offset nzwi2
						mov al,0d                       ;plik tylko do odczytu
						mov ah,3Dh                      ;proba otwarcia
						int 21h
						JC fileerr                      ;w razie bledu skok do fileerr
						mov ds:[grip2],ax       		;uchwyt do pliku w grab2

						pop dx                          ;przywrocenie rejestrow i powrot do programu.
						pop cx
						pop bx
						pop ax
						ret

		OPENTHREE endp

        ;================================READTOBUF===================================

		READTOBUF proc
				push ax							;procedura czyta do bufora buffer.
				push bx
				push cx
				push dx
				;---------------------------
				mov ds:[eof],0d					;poczatkowo flaga eof = false;
				mov ds:[buflen],0d				;poczatkowo 0 znakow wczytanych.
				mov bx,ds:[grip1]               ;uchwyt pliku do odczytu w BX
				mov cx,500d                     ;liczba bajtow do odczytu.
				mov dx,offset buffer            ;bufor w DS:DX
				mov ah,3Fh                      ;przerwanie odczytu z pliku
				int 21h
				
				mov ds:[inferr],ax              ;komunikat o ew. bledzie do inferr.
				JC fileerr                      ;w razie problemu skok do komunikatu.
				mov ds:[buflen],ax				;ile znakow wczytano?
				cmp al,0d						;czy plik sie skonczyl (bufor pusty)?
				JNE finbuf						;jesli nie, skocz do finbuf
				mov ds:[eof],1d					;jesli tak, ustaw flage eof.
				;-----------------------------
			finbuf:
				mov ds:[currentbuf],offset buffer	;aktualne polozenie w buforze = 0.
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		READTOBUF endp
	
	;=========================================SAVETOFILE======================================
	
		SAVETOFILE proc
				push ax							;zapis sumy CRC do pliku.
				push bx
				push cx
				push dx
				;--------------------
				call PACKCRC					;pakowanie sumy do odpowiedniej formy hex.
				mov bx,ds:[grip2]               ;uchwyt pliku do zapisu w BX
				mov cx,6d	              		;liczba bajtow do zapisania.
				mov dx,offset crcpack           ;suma CRC - 16 zapisana jako hex.
				mov ah,40h                      ;przerwanie zapisu do pliku
				int 21h
				mov ds:[inferr],ax              ;komunikat o ew. bledzie do inferr.
				JC fileerr                      ;w razie problemu skok do komunikatu.
				;--------------------
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		SAVETOFILE endp
		
        ;==================================GETCHAR====================================
		
		GETCHAR proc
				push ax									;odczyt pojedynczego znaku z bufora
				push bx									;do line.
				push cx									;offsety: buffer -> DI
				push dx									;line -> SI
				JMP startup								;rozpocznij
			
			linefeed:
				call READTOBUF							;zaladowanie kolejnej paczki
				cmp ds:[eof],0d							;czy plik sie skonczyl?
				JNE finishgetch							;jesli tak, zakoncz czytanie.
				mov ax,ds:[buflen]
				mov ds:[alread],ax						;jezeli nie, dlugosc bufora do licznika alread.
			
			startup:
				mov di,ds:[currentbuf]					;aktualne polozenie w buforze.
				cmp ds:[alread],0d
				JE linefeed								;jesli odczytano wszystkie znaki z bufora, zaladuj nowe.
				mov al,ds:[di]							;jeden znak z bufora do AL
				mov ds:[si],al							;a nastepnie do LINE.
				inc di									;przesuniecie w buforze
				inc si									;i w line.
				dec ds:[alread]							;licznik znakow pozostalych do odczytania z bufora.
				mov ds:[currentbuf],di					;zapisz aktuale polozenie w buforze.
				
			finishgetch:
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		GETCHAR endp
		
		;=============================GETLINE===========================================
		
		GETLINE proc
				push ax									;pobiera linijke z pliku do tablicy line.
				push bx
				push cx
				push dx
				
				mov si,offset line						;offset linijki w SI
			linestart:
				call GETCHAR							;wczytaj pojedynczy znak
				cmp ds:[eof],1d							;czy plik sie skonczyl?
				JE linefinish							;jesli tak, skocz do linefinish
				
				mov ax,10d
				cmp byte ptr ds:[si-1],al				;jezeli to byl znak nowej linii
				JE linefinish2							;nie czytamy dalej.
				JMP linestart
			
			linefinish:
				mov ax,13d
				mov byte ptr ds:[si],al					;informacja dla obliczen CRC - koniec pliku.
			linefinish2:
				inc si									;"ominiecie" LF.
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		GETLINE endp
		
		;=================================FILLTAB======================================
		
		FILLTAB proc
				push ax								;procedura wypelnia tablice crctab
				push bx								;danymi przydatnymi do obliczania CRC.
				push cx
				push dx
			;-----------------------------------------------
				xor dx,dx
				mov dl,1d
				mov cl,15d
				shl dx,cl							;w DX teraz (1<<15) uzywane wewnatrz petli.
				
				mov si,0d							;kolejne znaki ASCII a zarazem indeks tablicy.
				mov cx,256d							;dla kazdego znaku ASCII - petla.
			tbcrc:
				mov ax,si
				mov ds:[rev],ax						;znak w zmiennej rev.
				call REVBITS						;odbicie bitow.
				mov bx,9d							;licznik wewnetrzej petli.
				;------------------
				innercrc:
					dec bx
					cmp bx,0d
					JE fininner						;warunek wewnetrznej petli.
	
					push dx
					mov dx,ds:[rev]					;rev kopiowana do tstrev (zmiennej pomocniczej).
					mov ds:[tstrev],dx
					pop dx
					
					push cx
					mov cl,1d
					shl ds:[rev],cl					;przesuniecie kodu w lewo o 1 bit.
					pop cx
					
					and ds:[tstrev],dx				;tstrev = oryginalny_kod & (1<<15)
					cmp ds:[tstrev],0d				;czy (kod & 1<<15) =0?
					JNE notzero						;jesli nie, skocz do notzero.
					JMP innercrc					;petla wewnetrzna innercrc.	
				notzero:
					xor ds:[rev],pcrc				;dodatkowa roznica symetryczna wzgledem wielomianu P.
					JMP innercrc					;petla wewnetrzna innercrc.
				;-------------------------
				fininner:
				call REVBITS						;ponowne odbicie bitow.
				mov ax,ds:[rev]
				mov ds:[crctab + si],ax				;zaladowanie obliczonego kodu do tablicy crctab.
				inc si								;przesuniecie do kolejnego znaku.
				loop tbcrc
			;--------------------------------------------
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		FILLTAB endp
		
		;===================================REVBITS=================================
		
		REVBITS proc
			push ax										;procedura odwraca bity w zmiennej rev.
			push bx
			push cx
			push dx
			;--------------------------
			mov bx,17d									;licznik bitow
			mov ax,ds:[rev]								;zaladuj znak do AX.
			mov ds:[rev],0								;wyzeruj rev
			mov cl,1d
		reload:
			dec bx
			cmp bx,0d									;czy juz zamieniono wszystkie bity?
			JE finbit									;jesli tak, skocz do finbit.
			shl ds:[rev],cl								;przesun rev o 1 bit w lewo.
			shr ax,cl									;"wysun" jeden bit w prawo z AX.
			JC addition									;jesli to jedynka, skocz do addition.
			JMP reload
		addition:
			add ds:[rev],1d								;ustawienie najmlodszego aktualnie bitu na 1.
			JMP reload
			;---------------------------
		finbit:
			pop dx
			pop cx
			pop bx
			pop ax
			ret
		REVBITS endp
		
		;==================================CHECKSUM================================
		
		CHECKSUM proc
				push ax									;procedura oblicza CRC-16 dla
				push bx									;linii zapisanej w line.
				push cx									;wynik zapisywany jest w zmiennej crc.
				push dx
				;-----------------------------------
				xor ax,ax
				mov ds:[crc],ax							;wyzerowanie crc.
				mov ds:[crc],65535d						;crc = 2^16 - 1
				mov si,offset line
			countcrc:
				mov ax,13d
				cmp byte ptr ds:[si],al					;jezeli to nie jest znak nowej linii - kontynuuj.
				JE fincrc								;jesli byl, skocz do fincrc.
				
				mov ax,ds:[crc]
				mov ds:[tstrev],ax						;crc do pomocniczej tstrev.
				and ds:[tstrev],255d					;crc & 255 (pomocnicze).
				xor dx,dx
				mov dx,ds:[si]							;znak z line do dx.
				xor ds:[tstrev],dx						;tstrev = (crc & 255) XOR line[si]
				inc si									;przesuniecie na nastepny znak.
				mov di,ds:[tstrev]
				mov cl,8d
				shr ds:[crc],cl							;crc = crc>>8
				mov dx,ds:[di]
				xor ds:[crc],dx							;crc = (crc>>8) XOR crctab[(crc&255) XOR linia[]]
				
				JMP countcrc							;petla countcrc.
				
				;-------------------------------------
			fincrc:
				mov cx,65535d
				xor ds:[crc],cx							;crc = crc XOR (2^16 -1)
				
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		CHECKSUM endp
		
		;====================================PACKCRC===================================
		
		PACKCRC proc
				push ax									;procedura zamienia liczbe na znaki szesnastkowe
				push bx									;do wypisania (zapis do crcpack).
				push cx
				push dx
				;-------------------------------------
				xor cx,cx								;zerowanie licznika.
				mov ax,ds:[crc]							;crc do DX.
				mov bx,16d								;dzielnik = 16.
			petlapack:
				xor dx,dx								;wyzerowanie DX (tam znajdzie sie reszta).
				div bx									;dzielenie przez 16.
				push dx									;reszta z dzielenia na stos (odwracanie kolejnosci).
				inc cx
				cmp cx,4								;czy juz wykonano 4 razy?
				JNE petlapack
				
				mov si,offset crcpack					;offset tablicy docelowej do SI.
			gopack:
				pop dx									;sciagamy reszte ze stosu.
				cmp dx,9d								;klasyfikujemy ja odpowiednio.
				JA big
				add dx,48
				jmp gopack2
			big:
				add dx,55
			gopack2:
				mov ds:[si],dl							;dodajemy do tablicy.
				inc si
				loop gopack
				mov ax,13d
				mov byte ptr ds:[si],al
				inc si
				mov ax,10d
				mov byte ptr ds:[si],al					;dodanie "Enter" (CR+LF) na koniec pojedynczej sumy.

				;----------------------------------
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		PACKCRC endp
		
		;==============================CLOSEFILES=====================================
		
		CLOSEFILES proc
				push ax								;procedura zamyka oba otwarte pliki.
				push bx
				push cx
				push dx
				;------------------------------
				mov bx,ds:[grip1]					;uchwyty w grip1 oraz grip2.
				mov ah,3Eh							;przerwanie 3Eh zamyka plik.
				int 21h
				JC closeerr
				
				mov bx,ds:[grip2]
				int 21h
				JC closeerr
				;------------------------------
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		CLOSEFILES endp
		
		;===============================================================================

		CHOOSEVER proc
				push ax                     	;procedura wybiera odpowiednie zachowanie
				push bx                         ;programu w zaleznosci od ilosci argumentow.
				push cx
				push dx
				;-----------------------------

				cmp ds:[argz],2d                ;czy argumentow wejsciowych bylo 2?
				JNE targz                       ;jesli nie, skocz do targz
				call OPENTWO                    ;jesli tak, pierwsza wersja
				call GETFILECRC					;wariant 1.
				mov dx,offset komu9				;komunikat powodzenia zapisu.
				JMP finline                     ;skok na koniec
		targz:
				call OPENTHREE                  ;wersja druga
				call CMPFILESCRC				;wariant programu 2.
				mov dx,offset komu10			;komunikat powodzenia porownania.
				;----------------------------
		finline:
				mov ah,9						;wypisanie odpowiedniego komunikatu na ekran.
				int 21h
				
				pop dx
				pop cx
				pop bx
				pop ax
				ret                             ;powrot do programu.
		CHOOSEVER endp

        ;==========================GETFILECRC================================
		
		GETFILECRC proc
				push ax									;procedura wykonuje program w wariancie 1.
				push bx									;czyta plik wejsciowy i zapisuje sumy CRC
				push cx									;dla kazdej linii w pliku wyjsciowym.
				push dx
				;-----------------------------
				mov ds:[eof],0d							;inicjalizacja flagi EOF (=false).
				mov ds:[alread],0d						;liczba odczytanych znakow bufora = 0. (dla GETLINE).
			onebegin:
				cmp ds:[eof],0d							;czy przeczytano caly plik?
				JNE oneover								;jestli tak, skocz do oneover.
				call GETLINE							;pobierz jedna linie tekstu.
				call CHECKSUM							;oblicz sume kontrolna CRC-16.
				call SAVETOFILE							;zapisz wynik do pliku.
				JMP onebegin							;powtorz od onebegin.
				;-----------------------------
			oneover:
				pop dx									;ostatecznie GETLINE ustawi flage EOF i tym samym
				pop cx									;przerwie petle onebegin.
				pop bx
				pop ax
				ret
		GETFILECRC endp
		
		;======================================================================
		
		CMPFILESCRC proc
				push ax									;procedura wykonuje drugi wariant programu:
				push bx									;oblicza sumy kontrolne pliku 1 i porownoje je
				push cx									;z sumami zapisanymi w pliku 2.
				push dx
				;-----------------------------
				mov ds:[linecount],1d					;numer czytanej linii, poczatkowo 1.
				mov ds:[crceof],0d						;flaga eof dla crc = false.
				mov ds:[crcalread],0d					;liczba pozostalych znakow bufora crc = 0. (dla GETLINE).
				mov ds:[eof],0d							;inicjalizacja flagi EOF (=false).
				mov ds:[alread],0d						;liczba pozostalych znakow bufora = 0. (dla GETLINE).
			twobegin:
				call GETLINE							;pobierz jedna linie tekstu pliku 1.
				call CHECKSUM							;oblicz sume kontrolna CRC-16 pliku 1
				call GETONECRC							;pobierz jedna sume kontrolna z pliku 2.
				cmp ds:[crceof],0d						;czy przeczytano caly plik?
				JNE twoover								;jestli tak, skocz do twoover.
				call UNPACKCRC							;zapisz ja w liczbowej postaci.
				
				mov dx,ds:[crcread]						;suma odczytana z pliku 2 do DX.
				mov ax,ds:[crc]							;suma obliczona z linii pliku 1 do AX.
				cmp dx,ax								;porownanie sum CRC-16.
				JNE nonmatcherr							;w razie niezgodnosci, skok do bledu.
				inc ds:[linecount]						;numer czytanej linii ++.
				JMP twobegin							;powtorz od twobegin.
				
			nonmatcherr:
				mov dx,offset komu7        ;napis komunikatu do rejestru DX
				mov ah,9                   ;przerwanie nr 9 wypisuje lancuch zakonczony $
				int 21h                    ;komunikat o niezgodnosci sum kontrolnych.
				call NUMPRINT
				mov ah,4ch
				int 21h						;wyjscie z programu z bledem.
				;------------------------------
			twoover:
				cmp ds:[eof],0d				;czy oba pliki zostaly przeczytane do konca?
				JNE popover					;jesli tak, powodzenie.
				mov dx,offset komu8			;jesli nie - blad.
				mov ah,9
				int 21h
				mov ah,4ch
				int 21h						;wyjscie z programu z bledem.
				
			popover:	
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		CMPFILESCRC endp
		
		;============================UNPACKCRC============================
		
		UNPACKCRC proc
				push ax							;procedura przyjmuje liczbe hex zapisana w postaci czytelnej
				push bx							;i przetwarza ja do 16-bitowej zmiennej crcread.
				push cx
				push dx
				;-------------------------------
				
				mov cx,4d						;wejsciowy zapis CRC miesci sie na 4 znakach.
				xor ax,ax
				mov ds:[crcread],ax				;inicjalizacja.
				mov ax,1d
				mov ds:[mulkeeper],ax			;nasz poczatkowy mnoznik.
			unpack:
			
				mov si,offset crcpack			;ustawienie si w odpowiednim miejscu wejsciowej tablicy.
				dec si
				add si,cx
				xor bx,bx
				mov bl,ds:[si]					;pobranie znaku z tablicy do BX.
				cmp bx,65d						;klasyfikacja znaku, czy jest mniejszy od 'A'?
				JB decimalsub					;jesli tak, jest z zakresu 0-9.
				sub bx,55d						;jesli nie, jest z zakresu 'A' - 'F'.
				JMP multiplier
			decimalsub:
				sub bx,48d
			multiplier:
				xor ax,ax
				mov ax,ds:[mulkeeper]				;aktualny mnoznik do AX.
				mul bx								;DX:AX = AX * BX


				add ds:[crcread],ax					;dodanie obliczonej liczby do wyjsciowej zmiennej crcread.
				
				mov bx,ds:[mulkeeper]				;mnoznik = mnoznik * 16.
				mov ax,16d
				mul bx
				mov ds:[mulkeeper],ax				;zapisanie nowego mnoznika.
				loop unpack							;powtarzane dla wszystkich 4 znakow wejsciowych.
				;---------------------------------
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		UNPACKCRC endp
		
		;============================CRCREADER=================================
		
		CRCREADER proc
				push ax							;procedura odczytuje do 60-elementowego
				push bx							;bufora sumy CRC z pliku wejsciowego 2.
				push cx
				push dx
				
				;---------------------------
				mov ds:[crceof],0d				;poczatkowo flaga eof crc = false;
				mov ds:[crcbuflen],0d			;poczatkowo 0 znakow wczytanych.
				mov bx,ds:[grip2]               ;uchwyt pliku do odczytu w BX
				mov cx,60d 	                    ;liczba bajtow do odczytu.
				mov dx,offset crcbuffer         ;bufor crc w DS:DX
				mov ah,3Fh                      ;przerwanie odczytu z pliku
				int 21h
				
				mov ds:[inferr],ax              ;komunikat o ew. bledzie do inferr.
				JC fileerr                      ;w razie problemu skok do komunikatu.
				mov ds:[crcbuflen],ax			;ile znakow wczytano?
				cmp al,3d						;czy plik sie skonczyl (bufor ponizej 4 znakow)?
				JA finbufc						;jesli nie, skocz do finbufc
				mov ds:[crceof],1d				;jesli tak, ustaw flage eof crc.
				;-----------------------------
			finbufc:
				mov ds:[crccurrbuf],offset crcbuffer	;aktualne polozenie w buforze crc = 0.
				;------------------------
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		CRCREADER endp
		
		;=============================GETONECRC================================
		GETONECRC proc
				push ax									;procedura pobiera pojedyncza sume CRC-16
				push bx									;z pliku wejsciowego 2 do zmiennej CRCREAD.
				push cx									;odczyt jest buforowany.
				push dx
				JMP loadcrc
			
			reloadcrc:
				call CRCREADER
				cmp ds:[crceof],0d						;czy plik sie skonczyl?
				JNE stopgetcrc							;jesli tak, zakoncz czytanie.
				mov ax,ds:[crcbuflen]
				mov ds:[crcalread],ax					;jezeli nie, dlugosc bufora do licznika crcalread.
				
			loadcrc:
				cmp ds:[crcalread],0d					;jezeli przeczytano caly bufor
				JE reloadcrc							;nalezy przeladowac.
				mov cx,6d
				mov si,offset crcpack					;offset czytalnego HEXa do si.
				mov di,ds:[crccurrbuf]					;do di aktualne polozenie w buforze crc.
				crcpetla:								;powtarzamy 6 razy:
					mov al,ds:[di]						;znak z bufora crc do al
					mov ds:[si],al						;a nastepnie do crcpack
					inc si								;przesuniecie w obu tablicach.
					inc di
					dec ds:[crcalread]				;zmniejszenie licznika pozostalych danych w buforze crc.
				loop crcpetla

				mov ds:[crccurrbuf],di				;zapisz aktualne polozenie w buforze.
			stopgetcrc:
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		GETONECRC endp
		
		;============================NUMPRINT===================================
		
		NUMPRINT proc
				push ax						;procedura wypisuje zawartosc zmiennej linecount
				push bx						;w postaci dziesietnej na ekran.
				push cx
				push dx
				
				mov ax,ds:[linecount]
				xor cx,cx
				mov bx,10d
				
			diver:
				mov dx,0d					;standardowa dekonstrukcja liczby poprzez modulo.
				div bx						;kolejne reszty wrzucane na stos, w celu odwrocenia kolejnosci.
				push dx
				inc cx
				cmp ax,0d
				JNE diver
				
			printer:
				pop dx						;wypisanie reszt w odwrotnej kolejnosci daje faktyczna liczbe.
				add dx,48d
				mov ah,2
				int 21h
				loop printer
				
				pop dx
				pop cx
				pop bx
				pop ax
				ret
		NUMPRINT endp
		
		;======================================================================

        START:
        mov bx,ds
                                      ;Program Segment Prefix do BX
        mov es,bx                     ;przenosimy segment do ES dla procedury
        mov ax,data                   ;segment danych przeladowany
        mov ds,ax                     ;do DS
                ;----------------------------------------------------
                mov ax,seg stack      ;inicjalizacja stosu
                mov ss,ax
                mov sp,offset top
                ;----------------------------------------------------
				call LOADER           	;procedura loader-zaladuje arg. do tabl.
                call CHECKUP
                call FILLTAB
				call CHOOSEVER
				call CLOSEFILES

loltrol:
        mov ah,4ch                    ;zakonczenie programu.
        int 21h
        ;****************BLAD ilosci argumentow*************************
argerr:
        mov dx,offset komu1             ;napis komunikatu do rejestru DX
        mov ah,9                        ;przerwanie nr 9 wypisuje lancuch zakonczony $
        int 21h                         ;komunikat o zlej liczbie argumentow
        mov ah,4ch                      ;i zakonczenie programu.
        int 21h
        ;****************BLAD typu argumentow*************************
argtypeerr:
        mov dx,offset komu2        ;napis komunikatu do rejestru DX
        mov ah,9                   ;przerwanie nr 9 wypisuje lancuch zakonczony $
        int 21h                    ;komunikat o zlym typie argumentow (zakres danych)
        mov ah,4ch                 ;i zakonczenie programu.
        int 21h
        ;****************BLAD dlugosci argumentow*************************
arglenerr:
        mov dx,offset komu3        ;napis komunikatu do rejestru DX
        mov ah,9                   ;przerwanie nr 9 wypisuje lancuch zakonczony $
        int 21h                    ;komunikat o zlej dlugosci argumentow
        mov ah,4ch                 ;i zakonczenie programu.
        int 21h
        ;****************BLAD odczytu z pliku*****************************
fileerr:

                cmp ds:[inferr],3d      	;sprawdzenie rodzaju bledu.
                JA kom5                     ;blad dostepu: skok do kom5

                mov dx,offset komu4         ;plik nie odnaleziony etc.
                mov ah,9
                int 21h
                JMP komend
        kom5:
                mov dx,offset komu5         ;brak dostepu do pliku.
                mov ah,9d
                int 21h
        komend:
                mov ah,4ch                  ;koniec programu.
                int 21h

		;********************BLAD zamkniecia pliku***************************
closeerr:
		mov dx,offset komu6        ;napis komunikatu do rejestru DX
        mov ah,9                   ;przerwanie nr 9 wypisuje lancuch zakonczony $
        int 21h                    ;komunikat o zlej dlugosci argumentow
        mov ah,4ch                 ;i zakonczenie programu.
        int 21h


code ends
end START